package threadlocal;

import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.TtlExecutors;

/**
 * @author chaird
 * @create 2021-05-13 20:14
 */
public class TransmittableThreadLocalDemoMe {
    public static void main(String[] args) {

        //parent2child();


        undoChangeVal();


    }

    private static void undoChangeVal() {

        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(
                        1,
                        1,
                        20L,
                        TimeUnit.SECONDS,
                        new LinkedBlockingQueue<Runnable>(2),
                        Executors.defaultThreadFactory(),
                        new ThreadPoolExecutor.AbortPolicy());
        // 需要注意的是，使用TTL的时候，要想传递的值不出问题，线程池必须得用TTL加一层代理（下面会讲这样做的目的）
        ExecutorService executorService =
                TtlExecutors.getTtlExecutorService(threadPoolExecutor);
        // 这里采用TTL的实现
        TransmittableThreadLocal tl = new TransmittableThreadLocal<>();


        tl.set(LocalDateTime.now().toString());


        executorService.submit(
                () -> {
                    while (true) {
                        sleep(1000L);
                        System.out.println(
                                String.format(
                                        "线程名称-%s, 变量值=%s",
                                        Thread.currentThread().getName(), tl.get()));
                    }
                });


        while (true) {
            sleep(1000L);

            tl.set(LocalDateTime.now().toString());
        }


    }

    /**
     * 父传子
     */
    private static void parent2child() {
        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(
                        1,
                        1,
                        20L,
                        TimeUnit.SECONDS,
                        new LinkedBlockingQueue<Runnable>(2),
                        Executors.defaultThreadFactory(),
                        new ThreadPoolExecutor.AbortPolicy());
        // 需要注意的是，使用TTL的时候，要想传递的值不出问题，线程池必须得用TTL加一层代理（下面会讲这样做的目的）
        ExecutorService executorService =
                TtlExecutors.getTtlExecutorService(threadPoolExecutor);
        // 这里采用TTL的实现
        TransmittableThreadLocal tl = new TransmittableThreadLocal<>();


        String mainThreadName = "main";
        tl.set("1");//父线程，第一次赋值


        executorService.submit(
                () -> {
                    sleep(1L);
                    System.out.println(
                            String.format(
                                    "本地变量改变之前(1), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                                    mainThreadName, Thread.currentThread().getName(), tl.get()));
                });


        sleep(2000L); // 确保上面的会在tl.set执行之前执行
        System.out.println("sleep");
        tl.set(2); // 等上面的线程池第一次启用完了，父线程再给自己赋值


        executorService.execute(
                () -> {
                    sleep(1L);
                    System.out.println(
                            String.format(
                                    "本地变量改变之后(2), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                                    mainThreadName, Thread.currentThread().getName(), tl.get()));
                });
    }


    private static void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
